#include "OgreGLESPBRenderTexture.h"
#include "OgreGLESPBuffer.h"
#include "OgreGLESContext.h"
#include "OgreGLESPixelFormat.h"
#include "OgreGLESHardwarePixelBuffer.h"
#include "OgreLogManager.h"
#include "OgreStringConverter.h"
#include "OgreRoot.h"

namespace Ogre
{
	GLESPBuffer::GLESPBuffer(PixelComponentType format, size_t width, size_t height)
		: mFormat(format),
		  mWidth(width),
		  mHeight(height)
	{
	}

	GLESPBuffer::~GLESPBuffer()
	{
	}

	GLESPBRenderTexture::GLESPBRenderTexture(GLESPBRTTManager* manager, const String &name,
											const GLESSurfaceDesc& target,
											bool writeGamma, uint fsaa)
		: GLESRenderTexture(name, target, writeGamma, fsaa),
		  mManager(manager)
	{
		mPBFormat = PixelUtil::getComponentType(target.buffer->getFormat());
		mManager->requestPBuffer(mPBFormat, mWidth, mHeight);
	}

	GLESPBRenderTexture::~GLESPBRenderTexture()
	{
		mManager->releasePBuffer(mPBFormat);
	}

	void GLESPBRenderTexture::getCustomAttribute(const String& name, void* pData)
	{
		if (name == "TARGET")
		{
			GLESSurfaceDesc& target = *static_cast<GLESSurfaceDesc*>(pData);
			target.buffer = static_cast<GLESHardwarePixelBuffer*>(mBuffer);
			target.zoffset = mZOffset;
		}
	}

	GLESPBRTTManager::GLESPBRTTManager(GLESSupport* support, RenderTarget* mainwindow)
		: mSupport(support),
		  mMainWindow(mainwindow),
		  mMainContext(0)
	{
		mMainWindow->getCustomAttribute("GLCONTEXT", &mMainContext);
	}

	GLESPBRTTManager::~GLESPBRTTManager()
	{
		for (size_t x = 0; x < PCT_COUNT; ++x)
		{
			OGRE_DELETE mPBuffers[x].pb;
		}
	}

	RenderTexture* GLESPBRTTManager::createRenderTexture(const String& name,
														 const GLESSurfaceDesc& target,
														 bool writeGamma, uint fsaa)
	{
		return OGRE_NEW GLESPBRenderTexture(this, name, target, writeGamma, fsaa);
	}

	bool GLESPBRTTManager::checkFormat(PixelFormat format)
	{
		return true;
	}

	void GLESPBRTTManager::bind(RenderTarget* target)
	{
	}

	void GLESPBRTTManager::unbind(RenderTarget* target)
	{
		GLESSurfaceDesc surface;
		surface.buffer = 0;
		target->getCustomAttribute("TARGET", &surface);
		if (surface.buffer)
		{
			static_cast<GLESTextureBuffer*>(surface.buffer)->copyFromFramebuffer(surface.zoffset);
		}
	}

	void GLESPBRTTManager::requestPBuffer(PixelComponentType ctype, size_t width, size_t height)
	{
		if (mPBuffers[ctype].pb)
		{
			if (mPBuffers[ctype].pb->getWidth() < width ||
				mPBuffers[ctype].pb->getHeight() < height)
			{
				OGRE_DELETE mPBuffers[ctype].pb;
				mPBuffers[ctype].pb = 0;
			}
		}

		if (!mPBuffers[ctype].pb)
		{
			mPBuffers[ctype].pb = mSupport->createPBuffer(ctype, width, height);
		}
		++mPBuffers[ctype].refcount;
	}

	void GLESPBRTTManager::releaseBuffer(PixelComponentType ctype)
	{
		--mPBuffers[ctype].refcount;
		if (mPBuffers[ctype].refcount == 0)
		{
			OGRE_DELETE mPBuffers[ctype].pb;
			mPBuffers[ctype].pb = 0;
		}
	}
}
